//
//  Created by Jesse Squires
//  http://www.jessesquires.com
//
//
//  Documentation
//  http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
//  GitHub
//  https://github.com/jessesquires/JSQMessagesViewController
//
//
//  License
//  Copyright (c) 2014 Jesse Squires
//  Released under an MIT license: http://opensource.org/licenses/MIT
//

#import "JSQLocationMediaItem.h"
#import "JSQMessageTools.h"
#import "JSQMessagesMediaPlaceholderView.h"
#import "JSQMessagesMediaViewBubbleImageMasker.h"



@interface JSQLocationMediaItem ()

@property (strong, nonatomic) UIImage *cachedMapSnapshotImage;

@property (strong, nonatomic) UIImageView *cachedMapImageView;

@property (weak, nonatomic) UILabel *titleLabel;

- (void)createMapViewSnapshotForLocation:(CLLocation *)location
                        coordinateRegion:(MKCoordinateRegion)region
                   withCompletionHandler:(JSQLocationMediaItemCompletionBlock)completion;

@end


@implementation JSQLocationMediaItem

#pragma mark - Initialization

- (instancetype)initWithLocation:(CLLocation *)location locationTitle:(NSString *)locationTitle {
    self = [super init];
    if (self) {
        [self setLocation:location withLocationTitle:locationTitle withCompletionHandler:nil];
    }
    return self;
}

- (void)dealloc {
    _locationTitle = nil;
    _location = nil;
    _cachedMapSnapshotImage = nil;
    _cachedMapImageView = nil;
    _titleLabel = nil;
}

- (void)clearCachedMediaViews {
    [super clearCachedMediaViews];
    _cachedMapImageView = nil;
}

- (NSString *)key:(CLLocation *)location {
    NSString *key = [NSString stringWithFormat:@"%f%f", location.coordinate.latitude, location.coordinate.longitude];
    return [key stringByReplacingOccurrencesOfString:@"." withString:@""];
}

#pragma mark - Setters

- (void)setLocation:(CLLocation *)location {
    [self setLocation:location withLocationTitle:nil withCompletionHandler:nil];
}

- (void)setAppliesMediaViewMaskAsOutgoing:(BOOL)appliesMediaViewMaskAsOutgoing {
    [super setAppliesMediaViewMaskAsOutgoing:appliesMediaViewMaskAsOutgoing];
    _cachedMapSnapshotImage = nil;
    _cachedMapImageView = nil;
}

#pragma mark - Map snapshot

- (void)setLocation:(CLLocation *)location withLocationTitle:(NSString *)locationTitle withCompletionHandler:(JSQLocationMediaItemCompletionBlock)completion {
    [self setLocation:location withLocationTitle:locationTitle region:MKCoordinateRegionMakeWithDistance(location.coordinate, 500.0, 500.0) withCompletionHandler:completion];
}

- (void)setLocation:(CLLocation *)location withLocationTitle:(NSString *)locationTitle region:(MKCoordinateRegion)region withCompletionHandler:(JSQLocationMediaItemCompletionBlock)completion {
    _location = location;
    _locationTitle = locationTitle;

    if (_location == nil) {
        return;
    }

    [self createMapViewSnapshotForLocation:_location coordinateRegion:region withCompletionHandler:completion];
}

- (void)createMapViewSnapshotForLocation:(CLLocation *)location
                        coordinateRegion:(MKCoordinateRegion)region
                   withCompletionHandler:(JSQLocationMediaItemCompletionBlock)completion {
    NSParameterAssert(location != nil);

    NSString *key = [self key:location];
    if (key && key.length) {
        NSString *imagePath = [JSQMessageTools imagePath:key];
        UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
        if (image) {
            self.cachedMapSnapshotImage = image;
            return;
        }
    }

    MKMapSnapshotOptions *options = [[MKMapSnapshotOptions alloc] init];
    options.region = region;
    options.size = [self mediaViewDisplaySize];
    options.scale = [UIScreen mainScreen].scale;

    MKMapSnapshotter *snapShotter = [[MKMapSnapshotter alloc] initWithOptions:options];

    __weak typeof(self) VC = self;
    [snapShotter startWithQueue:dispatch_queue_create("AccessGeographicLocationQueue", DISPATCH_QUEUE_SERIAL)
              completionHandler:^(MKMapSnapshot *snapshot, NSError *error) {
        __strong typeof(VC) SVC = VC;
        if (error) {
            NSLog(@"%s Error creating map snapshot: %@", __PRETTY_FUNCTION__, error);
            return;
        }

        MKAnnotationView *pin = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:nil];
        CGPoint coordinatePoint = [snapshot pointForCoordinate:location.coordinate];
        UIImage *image = snapshot.image;

        coordinatePoint.x += pin.centerOffset.x - (CGRectGetWidth(pin.bounds) / 2.0);
        coordinatePoint.y += pin.centerOffset.y - (CGRectGetHeight(pin.bounds) / 2.0);

        UIGraphicsBeginImageContextWithOptions(image.size, YES, image.scale);

        [image drawAtPoint:CGPointZero];
        [pin.image drawAtPoint:coordinatePoint];
        SVC.cachedMapSnapshotImage = UIGraphicsGetImageFromCurrentImageContext();

        UIGraphicsEndImageContext();

        NSString *key = [SVC key:location];
        if (key && key.length) {
            NSData *imageData = UIImagePNGRepresentation(SVC.cachedMapSnapshotImage);
            NSString *imagePath = [JSQMessageTools imagePath:key];
            [imageData writeToFile:imagePath atomically:YES];
        }

        if (completion) {
            dispatch_async(dispatch_get_main_queue(), completion);
        }
    }];
}

#pragma mark - MKAnnotation

- (CLLocationCoordinate2D)coordinate {
    return self.location.coordinate;
}

#pragma mark - JSQMessageMediaData protocol

- (UIView *)mediaView {
    if (self.location == nil || self.cachedMapSnapshotImage == nil) {
        return nil;
    }

    if (self.cachedMapImageView == nil) {
        UIImageView *imageView = [[UIImageView alloc] initWithImage:self.cachedMapSnapshotImage];
        imageView.frame = CGRectMake(0, 0, [self mediaViewDisplaySize].width, [self mediaViewDisplaySize].height);
        imageView.contentMode = UIViewContentModeScaleAspectFill;
        imageView.clipsToBounds = YES;
        [JSQMessagesMediaViewBubbleImageMasker applyBubbleImageMaskToMediaView:imageView isOutgoing:self.appliesMediaViewMaskAsOutgoing];
        self.cachedMapImageView = imageView;

        UILabel *textLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, [self mediaViewDisplaySize].height - 35, [self mediaViewDisplaySize].width, 35)];
        textLabel.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.8];
        textLabel.textColor = [UIColor whiteColor];
        textLabel.textAlignment = NSTextAlignmentCenter;
        textLabel.userInteractionEnabled = NO;

        textLabel.font = [UIFont systemFontOfSize:13];
        [self.cachedMapImageView addSubview:textLabel];

        self.titleLabel = textLabel;

        if (self.locationTitle) {
            self.titleLabel.hidden = NO;
            self.titleLabel.text = self.locationTitle;
        } else {
            self.titleLabel.hidden = YES;
        }
    }



    return self.cachedMapImageView;
}

- (CGSize)mediaViewDisplaySize {
    if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
        return CGSizeMake(315.0f, 225.0f);
    }

    return CGSizeMake(220.0f, 160.0f);
}

- (NSUInteger)mediaHash {
    return self.hash;
}

#pragma mark - NSObject

- (BOOL)isEqual:(id)object {
    if (![super isEqual:object]) {
        return NO;
    }

    JSQLocationMediaItem *locationItem = (JSQLocationMediaItem *)object;

    return [self.location isEqual:locationItem.location];
}

- (NSUInteger)hash {
    return super.hash ^ self.location.hash;
}

- (NSString *)description {
    return [NSString stringWithFormat:@"<%@: location=%@, appliesMediaViewMaskAsOutgoing=%@>",
            [self class], self.location, @(self.appliesMediaViewMaskAsOutgoing)];
}

#pragma mark - NSCoding

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        CLLocation *location = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(location))];
        [self setLocation:location withLocationTitle:nil withCompletionHandler:nil];
    }
    return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder {
    [super encodeWithCoder:aCoder];
    [aCoder encodeObject:self.location forKey:NSStringFromSelector(@selector(location))];
}

#pragma mark - NSCopying

- (instancetype)copyWithZone:(NSZone *)zone {
    JSQLocationMediaItem *copy = [[[self class] allocWithZone:zone] initWithLocation:self.location locationTitle:self.locationTitle];
    copy.appliesMediaViewMaskAsOutgoing = self.appliesMediaViewMaskAsOutgoing;
    return copy;
}

@end
